from flask_shop import db
from datetime import datetime
from werkzeug.security import generate_password_hash, check_password_hash


# class BaseModel:  # 这种写法可以不用写：__abstract__ = True
class BaseModel(db.Model):
    """模型基类，为每个模型补充创建时间和更新时间"""
    __abstract__ = True  # 抽象表为True，代表当前类为基类，当前对象不会创建成表
    create_time = db.Column(db.DateTime, default=datetime.utcnow)
    update_time = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)


class User(BaseModel):
    __tablename__ = 't_user'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(32), unique=True, nullable=False)
    pwd = db.Column(db.String(128))
    nickname = db.Column(db.String(32))
    phone = db.Column(db.String(11))
    email = db.Column(db.String(32))

    role_id = db.Column(db.Integer, db.ForeignKey('t_role.id'))

    @property
    def password(self):
        return self.pwd

    @password.setter
    def password(self, t_pwd):
        self.pwd = generate_password_hash(t_pwd, method='pbkdf2:sha256')  # 这儿可以去掉生成的密码的前缀

    def check_password(self, t_pwd):
        return check_password_hash(self.pwd, t_pwd)

    def to_dict(self):
        return {
            'id': str(self.id),
            'name': self.name,
            'nickname': self.nickname,
            'phone': self.phone,
            'email': self.email,
            'role_name': self.role.name if self.role else '',
            'create_time': str(self.create_time),
            'update_time': str(self.update_time)
        }


# 该张表一定要出现在Menu和Role表上面
trm = db.Table('t_role_menu', db.Column('role_id', db.Integer, db.ForeignKey('t_role.id')),
               db.Column('menu_id', db.Integer, db.ForeignKey('t_menu.id')))


class Menu(db.Model):
    __tablename__ = 't_menu'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(32), unique=True, nullable=False)
    level = db.Column(db.Integer)
    path = db.Column(db.String(32))

    pid = db.Column(db.Integer, db.ForeignKey('t_menu.id'))
    children = db.relationship('Menu')
    roles = db.relationship('Role', secondary=trm)

    def to_dict(self):
        return {
            'id': self.id,
            'name': self.name,
            'level': self.level,
            'path': self.path,
            'pid': self.pid,
            # 'children': self.get_children_list()
        }

    def get_children_list(self):
        obj_child = self.children
        data = []
        for child in obj_child:
            data.append(child.to_dict())
        return data


class Role(db.Model):
    __tablename__ = 't_role'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(32), unique=True, nullable=False)
    desc = db.Column(db.String(128))

    users = db.relationship('User', backref='role')
    menus = db.relationship('Menu', secondary=trm)

    def to_dict(self):
        return {
            'id': self.id,
            'name': self.name,
            'desc': self.desc,
            'menus': self.get_menu_dict()
        }

    def get_menu_dict(self):
        menu_list = []
        menus_sorted = sorted(self.menus, key=lambda x: x.id)
        for menu in menus_sorted:
            if menu.level == 1:
                first_dict = menu.to_dict()
                first_dict['children'] = []
                for child_menu in menus_sorted:
                    if child_menu.level == 2 and child_menu.pid == menu.id:
                        first_dict['children'].append(child_menu.to_dict())
                menu_list.append(first_dict)
        return menu_list
